package com.mchat.ratelimit;

import com.mchat.exceptions.CommonException;
import com.mchat.ratelimit.dto.BaseDTO;
import com.mchat.ratelimit.strategy.AbstractRateLimitStrategy;
import com.mchat.ratelimit.strategy.StrategyFactory;
import org.springframework.http.HttpStatus;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class RateLimit {
    /**
     * 返回mono/flux的限流方法
     * @param param 限流对象的参数如uid，email
     * @param functionName 限流的方法名称或其他的唯一标识符
     * @param strategyName 限流的策略
     * @param count 单位时间内允许请求的次数
     * @param second 请求时间
     * @return false,向下传递以继续执行后续的方法或抛出异常
     */
    public static Mono<?> monoType(String param,String functionName,String strategyName,int count,int second){
        BaseDTO baseDTO = buildDTO(param, functionName, count, second);
        AbstractRateLimitStrategy strategy = StrategyFactory.get(strategyName);
        return strategy.reachRateLimit(baseDTO).map(v->{
            if (v)throw new CommonException("请求过于频繁，每"+second+"秒只能请求"+count+"次", HttpStatus.TOO_MANY_REQUESTS.value(),"请求过于频繁");
            return false;
        });
    }

    public static Flux<?> fluxType(String param,String functionName,String strategyName,int count,int second){
        BaseDTO baseDTO = buildDTO(param, functionName, count, second);
        AbstractRateLimitStrategy strategy = StrategyFactory.get(strategyName);
        return strategy.reachRateLimit(baseDTO).flatMapMany(v->{
            if (v) return Flux.error(new CommonException("请求过于频繁，每"+second+"秒只能请求"+count+"次", HttpStatus.TOO_MANY_REQUESTS.value(),"请求过于频繁"));
            return Flux.just(false);
        });
    }
    private  static BaseDTO buildDTO(String param, String functionName, int count, int second) {
        StringBuilder key = new StringBuilder(64).append(functionName).append(':').append(param);
        return new BaseDTO(key, second, count);
    }
}
